//
//	HOME AUTOMATION GATEWAY PROJECT
//
//  (c) 2008 mocom software GmbH & Co KG
//	for European Microsoft Innovation Center
//
//  $Author: volker $
//  $Date: 2009-06-20 17:15:06 +0200 (Sa, 20. Jun 2009) $
//  $Revision: 388 $
//
//  Microsoft dotNetMF Project
//  Copyright ©2001,2002,2003,2004 Microsoft Corporation
//  One Microsoft Way, Redmond, Washington 98052-6399 U.S.A.
//  All rights reserved.
//  MICROSOFT CONFIDENTIAL
//
//-----------------------------------------------------------------------------
#include "rtip.h"
#include "sock.h"
#include "rtipapi.h"
#include "rtpirq.h"
#include "rtp.h"
#include "rtpprint.h"
#include "rtpnet.h"

#include <tinyhal.h>
//#define IF_ACCESS_8BIT	1		// comment out for 16-Bit Interface
#include "AX88796B.h"

//#define MAC_MODE		SPEED_DUPLEX_100FD
#define MAC_MODE_TXT	"SPEED_DUPLEX_100FD"
//--//
/* ********************************************************************
   DEBUG AIDS
   ******************************************************************** */
#define DEBUG_AX88796B 0

#ifndef NETWORK_INTERFACE_INDEX_AX88796B
#define NETWORK_INTERFACE_INDEX_AX88796B 0
#endif

typedef struct {
	UINT32	id;
	UINT16	w[3];
} JMacAddr;

const JMacAddr *g_MacAddr = (JMacAddr*) MAC_ADDR_FROM_JACK;

extern "C"
{
	extern void rtp_thrd_interrupt_continuation(int);
	extern void rtp_thrd_ip_continuation(int);
}   /* extern "C" */

RTP_BOOL    AX88796B_open       (PIFACE pi);
void        AX88796B_close      (PIFACE pi);
int         AX88796B_xmit       (PIFACE pi, DCU msg);
RTP_BOOL    AX88796B_xmit_done  (PIFACE pi, DCU msg, RTP_BOOL success);
void        AX88796B_recv       (PIFACE pi);
RTP_BOOL    AX88796B_statistics (PIFACE pi);
void        AX88796B_interrupt  (PIFACE pi);

/* ********************************************************************
   GLOBAL DATA
   ******************************************************************** */
EDEVTABLE RTP_FAR AX88796B_mac_device =
{
    AX88796B_open,
    AX88796B_close,
    AX88796B_xmit,
    NULLP_FUNC,
    NULLP_FUNC,
    AX88796B_statistics,
    NULLP_FUNC,
    AX88796B_DEVICE,
    "AX88796B",
    MINOR_0,
    ETHER_IFACE,
    SNMP_DEVICE_INFO(CFG_OID_AX88796B_EMAC, CFG_SPEED_AX88796B_EMAC)
    CFG_ETHER_MAX_MTU,
    CFG_ETHER_MAX_MSS,
    CFG_ETHER_MAX_WIN_IN,
    CFG_ETHER_MAX_WIN_OUT,
    IOADD(0),
    EN(0),
    EN(0)
};

extern  NETWORK_CONFIG		g_NetworkConfig;

static AX88796B_SOFTC 		AX88796B_softc;

#define iface_to_softc(X) 	(AX88796B_SOFTC *) &AX88796B_softc;
#define off_to_softc(X)   	(AX88796B_SOFTC *) &AX88796B_softc;

static void printip(char *name, UINT8 *ip)
{
	debug_printf("%s: %3.3u.%3.3u.%3.3u.%3.3u\r\n",name,ip[0],ip[1],ip[2],ip[3]);
}

static void ax_select_page(UINT8 page)
{
	UINT8	cmdreg;

	page &= 0x3;
	cmdreg = ax_read_reg8(NIC_COMMAND);
	ax_write_reg8(NIC_COMMAND,(cmdreg & 0x3f) | (page << 6));
}

int ax_wait_rdy()
{
	while (( ax_read_reg8(NIC_DSR) & 0x20) == 0);
	return TRUE;
}

static void ax_read_blk(UINT32 *data, unsigned len, UINT8 page)
{
	UINT16 *r;
	unsigned blks,residue;

	// align len to 16-bit-words
	len = (len+1) & ~1;

	// we transfer blks of 4 long words = 8 words = 16 bytes
	blks 	= (len >> 4);
	// residue in 16-bit word transfers
	residue = (len & 0xf) >> 1;

	// start AX88796B internal DMA
	ax_write_reg8(NIC_RMT_ADDR_LSB,4);
	ax_write_reg8(NIC_RMT_ADDR_MSB,page);
	ax_write_reg8(NIC_RMT_COUNT_LSB,len&0xff);
	ax_write_reg8(NIC_RMT_COUNT_MSB,len>>8);
	ax_write_reg8(NIC_COMMAND,(CR_START | CR_DMA_READ));
	ax_wait_rdy();

	// move in 4 long words = 8 words = 16 bytes
	while (blks--) {
		// we read two 16-Bit words, join them and store a 32-Bit word. ARM loves it!
		*data++ = (((UINT32)ax_read_reg16(NIC_RACK_NIC)) << 16) | ((UINT32)ax_read_reg16(NIC_RACK_NIC));
		*data++ = (((UINT32)ax_read_reg16(NIC_RACK_NIC)) << 16) | ((UINT32)ax_read_reg16(NIC_RACK_NIC));
		*data++ = (((UINT32)ax_read_reg16(NIC_RACK_NIC)) << 16) | ((UINT32)ax_read_reg16(NIC_RACK_NIC));
		*data++ = (((UINT32)ax_read_reg16(NIC_RACK_NIC)) << 16) | ((UINT32)ax_read_reg16(NIC_RACK_NIC));
	}

	// need to read residue words
	r = (UINT16 *) data;

	// residue 16-bit-words transfers
	while (residue--) {
		*r++ = ax_read_reg16(NIC_RACK_NIC);
	}
}

static void ax_write_blk(UINT32 *data, unsigned len, UINT8 page)
{
	UINT16	*r;
	unsigned blks,residue;
	UINT32	a;

	// align len to 16-bit-words
	len = (len+1) & ~1;
	// we transfer blks of 8 words/16 bytes
	blks 	= (len >> 4);
	// residue 16-bit-word transfers
	residue = (len & 0xf) >> 1;

	// start DMA
	ax_write_reg8(NIC_RMT_ADDR_LSB,0);
	ax_write_reg8(NIC_RMT_ADDR_MSB,page);
	ax_write_reg8(NIC_RMT_COUNT_LSB,len&0xff);
	ax_write_reg8(NIC_RMT_COUNT_MSB,len>>8);
	ax_write_reg8(NIC_COMMAND,(CR_START | CR_DMA_WRITE));

	// move out 4 long words/32 bytes
	while (blks--) {
		a = *data++;
			ax_write_reg16(NIC_RACK_NIC,(UINT16) a);
			ax_write_reg16(NIC_RACK_NIC,(UINT16) (a>>16));
		a = *data++;
			ax_write_reg16(NIC_RACK_NIC,(UINT16) a);
			ax_write_reg16(NIC_RACK_NIC,(UINT16) (a>>16));
		a = *data++;
			ax_write_reg16(NIC_RACK_NIC,(UINT16) a);
			ax_write_reg16(NIC_RACK_NIC,(UINT16) (a>>16));
		a = *data++;
			ax_write_reg16(NIC_RACK_NIC,(UINT16) a);
			ax_write_reg16(NIC_RACK_NIC,(UINT16) (a>>16));
	}

	// need to write residue words
	r = (UINT16 *) data;

	// residue transfers
	while (residue--) {
		ax_write_reg16(NIC_RACK_NIC,(UINT16) *r++);
	}
}

RTP_BOOL AX88796B_SetupDevice(AX88796B_SOFTC *sc)
{
	UINT8 	accu;
	UINT16  data;
	UINT32 	timeout;

	//debug_printf("ETH: AX88796B DRIVER\r\n");

	// issue reset
	accu = ax_read_reg8(NIC_RESET);

	// wait for ready, with timeout
	for (timeout=1000;timeout>0;timeout--) {
		if (ax_read_reg8(NIC_DSR) & 0x10) {
			break;
		}
		IDelayLoop (100);
	}

	if (timeout == 0) {
		debug_printf("ETH: No hardware found, exit!\r\n");
		return RTP_FALSE;
	}

	data = MiiReadRegister(0x2);
	if (data != 0x3b) {
		debug_printf("ETH: Wrong ORG-ID, exit!\r\n");
		return RTP_FALSE;
	}

	data = MiiReadRegister(0x3);
	if (data != 0x1841) {
		debug_printf("ETH: Wrong PHY-ID, exit!\r\n");
		return RTP_FALSE;
	}

#ifdef IF_ACCESS_8BIT
	debug_printf("ETH: AX88796B CHIP FOUND, USING 8-Bit access\r\n");
#else
	debug_printf("ETH: AX88796B CHIP FOUND, USING 16-Bit access\r\n");
#endif

	sc->ax_tx_buffer_full = 0;
	sc->ax_current_tx_page = XMIT_START_PAGE;
	//sc->ax_current_rx_page = RCV_START_PAGE;

	// init registers page 0
	ax_write_reg8(NIC_COMMAND,CR_STOP | CR_PAGE0 | CR_STOP_DMA);		// page 0, stop
	ax_write_reg8(NIC_INTR_MASK,0x00);		// no interrupts
	ax_write_reg8(NIC_DATA_CONFIG,DCR_WORD_WIDE|0x80);			// 16-Bit Wide data port
	ax_write_reg8(NIC_PAGE_START,RCV_START_PAGE);				// PAGE START
	ax_write_reg8(NIC_PAGE_STOP,RCV_STOP_PAGE);					// PAGE STOP
	ax_write_reg8(NIC_BOUNDARY,RCV_START_PAGE);					// PAGE BOUNDRAY
	ax_write_reg8(NIC_CURRENT,RCV_START_PAGE+1);
	ax_write_reg8(NIC_INTR_STATUS,0xff);						// clear all ints

	// init registers page 1
	ax_write_reg8(NIC_COMMAND,CR_STOP | CR_PAGE1 | CR_STOP_DMA);		// select page 1
	ax_write_reg8(NIC_PHYS_ADDR+0,sc->mac_addr[0]);
	ax_write_reg8(NIC_PHYS_ADDR+1,sc->mac_addr[1]);
	ax_write_reg8(NIC_PHYS_ADDR+1,sc->mac_addr[1]);
	ax_write_reg8(NIC_PHYS_ADDR+2,sc->mac_addr[2]);
	ax_write_reg8(NIC_PHYS_ADDR+3,sc->mac_addr[3]);
	ax_write_reg8(NIC_PHYS_ADDR+4,sc->mac_addr[4]);
	ax_write_reg8(NIC_PHYS_ADDR+5,sc->mac_addr[5]);
	
	/*debug_printf( "mac: %2.2x%2.2x.%2.2x%2.2x.%2.2x%2.2x\r\n", 
				sc->mac_addr[0], 
				sc->mac_addr[1],                                                                 
				sc->mac_addr[2], 
				sc->mac_addr[3],                                                            
				sc->mac_addr[4], 
				sc->mac_addr[5] );												
	*/
	
	// accept ANY multicast addr
	for (int i=0;i<8;i++) {
		ax_write_reg8(NIC_MC_ADDR+i,-1);
	}
	
	// more init page 0
	ax_write_reg8(NIC_COMMAND,CR_STOP | CR_PAGE0 | CR_STOP_DMA);			// page 0, stop
	ax_write_reg8(NIC_FLOW_CONTROL,0xc7);	// flow ctrl + back press

	// enable pause
	data = MiiReadRegister(0x4);
	MiiWriteRegister(0x4,data | (1 << 10));

#ifdef MAC_MODE
	MiiWriteRegister(0x0,MAC_MODE);
	debug_printf("MODE: %s\r\n",MAC_MODE_TXT);
#else
	// start autonegociate
	data = MiiReadRegister(0x0);
	MiiWriteRegister(0x0,data | (1 << 9));
#endif
	
	ax_write_reg8(NIC_MAC_CONFIG,0x20);	// back-to-back

	// init page 3
	ax_write_reg8(NIC_COMMAND,CR_STOP | CR_PAGE3 | CR_STOP_DMA);		// select page 3
	ax_write_reg8(NIC_MISC_CONFIG,0x01);	// enable tx-ring

	// more init page 0
	ax_write_reg8(NIC_COMMAND,CR_STOP | CR_PAGE0 | CR_STOP_DMA);		// page 0, stop
	ax_write_reg8(NIC_XMIT_START,XMIT_START_PAGE);
	ax_write_reg8(NIC_RCV_CONFIG,0x44 | 0x8);		// accept multicast & broadcast

	// enable interrupts
	ax_write_reg8(NIC_BUFFER_TYPE_CFG,0x20); // Int push-pull, active low
	ax_write_reg8(NIC_INTR_MASK,0x2f);
	// enable chip
	ax_write_reg8(NIC_COMMAND,CR_START | CR_PAGE0 | CR_STOP_DMA);

    return RTP_TRUE;
}


RTP_BOOL AX88796B_open(PIFACE pi)
{
    AX88796B_SOFTC *sc = iface_to_softc(pi);
	int macLen = 0;

	//debug_printf("AX88796B_open\r\n");

    if (!sc)
    {
        RTP_DEBUG_ERROR("ETH: softc invalid!\r\n", NOVAR, 0, 0);
        set_errno(ENUMDEVICE);
        return(RTP_FALSE);
    }

    // Clear & Set Interface
	memset(sc,0,sizeof(sc));
    sc->iface = pi;

	macLen = __min(g_NetworkConfig.NetworkInterfaces[NETWORK_INTERFACE_INDEX_AX88796B].macAddressLen, sizeof(sc->mac_addr));
	if (g_MacAddr && g_MacAddr->id == 12) 
	{
		// import mac addr from JACK
		g_NetworkConfig.NetworkInterfaces[NETWORK_INTERFACE_INDEX_AX88796B].macAddressBuffer[0] = g_MacAddr->w[2] >> 8;
		g_NetworkConfig.NetworkInterfaces[NETWORK_INTERFACE_INDEX_AX88796B].macAddressBuffer[1] = g_MacAddr->w[2] & 0xff;
		g_NetworkConfig.NetworkInterfaces[NETWORK_INTERFACE_INDEX_AX88796B].macAddressBuffer[2] = g_MacAddr->w[1] >> 8;
		g_NetworkConfig.NetworkInterfaces[NETWORK_INTERFACE_INDEX_AX88796B].macAddressBuffer[3] = g_MacAddr->w[1] & 0xff;
		g_NetworkConfig.NetworkInterfaces[NETWORK_INTERFACE_INDEX_AX88796B].macAddressBuffer[4] = g_MacAddr->w[0] >> 8;
		g_NetworkConfig.NetworkInterfaces[NETWORK_INTERFACE_INDEX_AX88796B].macAddressBuffer[5] = g_MacAddr->w[0] & 0xff;
		macLen = 6;
	}
	if(macLen > 0)
    {
        memcpy(&sc->mac_addr[0], &g_NetworkConfig.NetworkInterfaces[NETWORK_INTERFACE_INDEX_AX88796B].macAddressBuffer[0], macLen);
    }
    else
    {
        RTP_DEBUG_ERROR("Device initialize without MAC address!!!\r\n", NOVAR, 0, 0);
    }
	
    /* Now put in a dummy ethernet address */
    rtp_memcpy(&pi->addr.my_hw_addr[0], sc->mac_addr, 6); // Get the ethernet address

    if(RTP_FALSE != AX88796B_SetupDevice(sc))
    {
		rtp_irq_hook_interrupt( (RTP_PFVOID) pi,
                            (RTP_IRQ_FN_POINTER)AX88796B_recv,
                            (RTP_IRQ_FN_POINTER) 0);
		return(RTP_TRUE);
	}

	return RTP_FALSE;
}


void AX88796B_close(PIFACE pi)                                /*__fn__*/
{
	//debug_printf("AX88796B_close\r\n");
    ARGSUSED_PVOID( pi );  /*  keep compiler happy */
}

#ifdef AX88796_IRQ_PIN
extern void AX88796B_interrupt(GPIO_PIN Pin, BOOL PinState, UINT32 minor)
#else
extern void AX88796B_interrupt(UINT32 minor)
#endif
{
    PIFACE          pi;
    UINT32 			ivec;
	AX88796B_SOFTC *sc = iface_to_softc(minor);


    /* get pi structure based on the minor number   */
    pi = sc->iface;

    if (pi)
    {
		GLOBAL_LOCK_SOCKETS(irq);

		// make sure we are in page 0
		ax_select_page(0);
		// disable interrupts
		ax_write_reg8(NIC_INTR_MASK,0x00);
		// get isr status
		ivec = ax_read_reg8(NIC_INTR_STATUS);
		// ack ints
		ax_write_reg8(NIC_INTR_STATUS,ivec);

		// handle isr
		if (ivec & ISR_RCV || ivec & ISR_RCV_ERR || ivec & ISR_OVERFLOW) {
			// execute AX88796B_recv
			//AX88796B_recv(pi);
			rtp_thrd_interrupt_continuation(pi->ctrl.index);
		}

		if (ivec & ISR_XMIT || ivec & ISR_XMIT_ERR) {
			sc->ax_tx_buffer_full = 0;
		    if(ivec & ISR_XMIT_ERR)
			{
				sc->stats.errors_out++;
				sc->stats.tx_other_errors++;
			}
			else
			{
				/* Update total number of successfully transmitted packets. */
				sc->stats.packets_out++;
			}
			rtp_net_invoke_output(pi, 1);
		}

		if (ivec & ISR_COUNTER) {
			sc->stats.rx_frame_errors += ax_read_reg8(NIC_FAE_ERR_CNTR);
			sc->stats.rx_crc_errors   += ax_read_reg8(NIC_CRC_ERR_CNTR);
			//sc->stats.rx_missed_errors+= ax_read_reg8(NIC_MISSED_CNTR);
		}

		// re-enable interrupts
		ax_write_reg8(NIC_INTR_MASK,0x2f);
	}
}

void AX88796B_recv(PIFACE pi)
{
    DCU					msg;
    UINT32				*dataTX;
    AX88796B_SOFTC 		*sc = iface_to_softc(pi);
	UINT16				plength;
	UINT16				pstatus;
	UINT8				current_page;
	UINT8				read_page;
	unsigned			cnt;

	cnt = 0;
	GLOBAL_LOCK_SOCKETS(irq);

	// make sure we are in page 0
	ax_select_page(0);

	// get nic current
	current_page = ax_read_reg8(NIC_CURRENT);
	read_page = ax_read_reg8(NIC_BOUNDARY) + 1;
	if (read_page >= RCV_STOP_PAGE)
		read_page = RCV_START_PAGE;

	// handle all pending packets
	while (current_page != read_page) {
		cnt++;
		// read header
		ax_write_reg8(NIC_RMT_ADDR_LSB,0);
		ax_write_reg8(NIC_RMT_ADDR_MSB,read_page);
		ax_write_reg8(NIC_RMT_COUNT_LSB,4);
		ax_write_reg8(NIC_RMT_COUNT_MSB,0);
		// start dma
		ax_write_reg8(NIC_COMMAND,(CR_START | CR_DMA_READ));
		// read 4 bytes
		pstatus = ax_read_reg16(NIC_RACK_NIC);
		plength = ax_read_reg16(NIC_RACK_NIC);
		plength -= 4;
		// get buffer and fill it if its a good packet!
		msg = NULL;
		if (pstatus & 1 && plength <= ETHERSIZE) {
			msg = os_alloc_packet_input(plength, DRIVER_ALLOC);
			if (msg) {
				msg->length = plength;
				dataTX = (UINT32 *) DCUTODATA(msg);
				// prepair read
				ax_read_blk(dataTX,plength,read_page);
				sc->stats.packets_in += 1;
				sc->stats.bytes_in += plength;
			} else {
				debug_printf("recv: FAIL in %u\r\n",__LINE__);
			}
		} else {
			sc->stats.errors_in++;
			debug_printf("recv: FAIL in %u\r\n",__LINE__);
		}

		read_page = (pstatus >> 8);
		if (read_page < RCV_START_PAGE ||
			read_page > RCV_STOP_PAGE) {
			debug_printf("recv: FAIL in %u\r\n",__LINE__);
			// this should not happen, reset ring
			read_page = RCV_START_PAGE;
			ax_write_reg8(NIC_CURRENT,read_page);
		}

		// free buffer
		if (read_page == RCV_START_PAGE) {
			ax_write_reg8(NIC_BOUNDARY,RCV_STOP_PAGE-1);
		} else {
			ax_write_reg8(NIC_BOUNDARY,read_page-1);
		}

		if (msg) {
			// signal IP layer that a packet is on its exchange
			rtp_net_invoke_input(pi, msg, plength);
		}
		// more to receive?
		current_page = ax_read_reg8(NIC_CURRENT);
	}

//	if (cnt == 0)
//		debug_printf("recv: FAIL in %u\r\n",__LINE__);
}

int AX88796B_xmit(PIFACE pi, DCU msg)
{
    RTP_UINT16      length = 0;
    UINT32			*dataTX;
	unsigned		pages,
					freepages,
					current;
	AX88796B_SOFTC 	*sc = iface_to_softc(pi);
	UINT8			ctepr;

	static unsigned	dbg_pages = 0;


    if (pi)
    {
		GLOBAL_LOCK_SOCKETS(irq);

		sc = iface_to_softc(pi);

		length = msg->length;
		if (length < ETHER_MIN_LEN)
		{
			length = ETHER_MIN_LEN;
		}

		// calc pages, aligned
		pages = (length+255) >> 8;
		// get datapointer
		dataTX = (UINT32 *)DCUTODATA(msg);
		// make sure we are in page 0
		ax_select_page(0);		// page 0
		current = sc->ax_current_tx_page;
		// get transmit end page and check for full
		ctepr = ax_read_reg8(NIC_CUR_TX_END_PAGE);
		if (ctepr & 0x80  || sc->ax_tx_buffer_full) {
			debug_printf("xmit: FAIL in %u\r\n",__LINE__);
			return (-1);
		}

		// calc freepages
		if(ctepr == 0) {
			if(current == XMIT_START_PAGE)
				freepages = XMIT_NUM_BUF;
			else
				freepages = XMIT_END_PAGE - current;
		}
		else if((current - 1) > ctepr) {
			freepages = (XMIT_END_PAGE - current) +
						 (ctepr - XMIT_START_PAGE + 1);
		}
		else if((current - 1) < ctepr) {
			freepages = ctepr - current + 1;
		}
		else if((current - 1) == ctepr) {
			freepages = XMIT_NUM_BUF;
		}

		// mark buffer full
		if (pages == freepages) {
			sc->ax_tx_buffer_full = TRUE;
		}

		// send if enough space
		if (pages <= freepages) {
			dbg_pages += pages;
			// dma data to buffer
			ax_write_blk(dataTX,length,current);
			// start transmission
			ax_write_reg8(NIC_XMIT_START,current);
			ax_write_reg8(NIC_XMIT_COUNT_LSB,length);
			ax_write_reg8(NIC_XMIT_COUNT_MSB,length >> 8);
			ax_write_reg8(NIC_COMMAND,CR_START | CR_XMIT | CR_STOP_DMA);
			// advance sc->ax_current_tx_page
			sc->ax_current_tx_page = current + pages;
			if (sc->ax_current_tx_page >= XMIT_END_PAGE) {
				sc->ax_current_tx_page -= XMIT_NUM_BUF;
			}
			// this >should< be counted in the isr, but its too diffcult to preserve
			// correct length until then.
			sc->stats.bytes_out += length;
			return (0);
		}
	}

	debug_printf("xmit: FAIL in %u\r\n",__LINE__);
	sc->stats.errors_out++;
	return (-1);
}

RTP_BOOL AX88796B_statistics(PIFACE pi)                       /*__fn__*/
{
#if (!INCLUDE_KEEP_STATS)
    ARGSUSED_PVOID(pi)
#endif

    if (!pi)
    {
        return RTP_FALSE;
    }

    UPDATE_SET_INFO(pi, interface_packets_in, AX88796B_packets_in)
    UPDATE_SET_INFO(pi, interface_packets_out, AX88796B_packets_out)
    UPDATE_SET_INFO(pi, interface_bytes_in, AX88796B_bytes_in)
    UPDATE_SET_INFO(pi, interface_bytes_out, AX88796B_bytes_out)
    UPDATE_SET_INFO(pi, interface_errors_in, AX88796B_errors_in)
    UPDATE_SET_INFO(pi, interface_errors_out, AX88796B_errors_out)
    UPDATE_SET_INFO(pi, interface_packets_lost, 0L)
    return(RTP_TRUE);
}

int xn_bind_AX88796B_mac(int minor_number)
{
	return(xn_device_table_add(AX88796B_mac_device.device_id,
						minor_number,
						AX88796B_mac_device.iface_type,
						AX88796B_mac_device.device_name,
					    SNMP_DEVICE_INFO(AX88796B_mac_device.media_mib,
						                 AX88796B_mac_device.speed)
   				        (DEV_OPEN)AX88796B_mac_device.open,
					    (DEV_CLOSE)AX88796B_mac_device.close,
					    (DEV_XMIT)AX88796B_mac_device.xmit,
					    (DEV_XMIT_DONE)AX88796B_mac_device.xmit_done,
					    (DEV_PROCESS_INTERRUPTS)AX88796B_mac_device.proc_interrupts,
					    (DEV_STATS)AX88796B_mac_device.statistics,
					    (DEV_SETMCAST)AX88796B_mac_device.setmcast));
}

